package terminal

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"k8s-admin/global"
	"k8s-admin/utils"
	"net/http"
	"strconv"
)

/*
*
实现流程：
	1.浏览器将主机的信息(ip, 用户名, 密码, 请求的终端大小等)进行加密, 传给后台, 并通过HTTP请求与后台协商升级协议. 协议升级完成后, 后续的数据交换则遵照web Socket的协议.
	2.后台将HTTP请求升级为web Socket协议, 得到一个和浏览器数据交换的连接通道
	3.后台将数据进行解密拿到主机信息, 创建一个SSH 客户端, 与远程主机的SSH 服务端协商加密, 互相认证, 然后建立一个SSH Channel
	4.后台和远程主机有了通讯的信道, 然后后台将终端的大小等信息通过SSH Channel请求远程主机创建一个 pty(伪终端), 并请求启动当前用户的默认 shell
	5.后台通过 Socket连接通道拿到用户输入, 再通过SSH Channel将输入传给pty, pty将这些数据交给远程主机处理后按照前面指定的终端标准输出到SSH Channel中, 同时键盘输入也会发送给SSH Channel
	6.后台从SSH Channel中拿到按照终端大小的标准输出后又通过Socket连接将输出返回给浏览器, 由此变实现了Web Terminal
*/

// 升级协议
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func ShellWs(ctx *gin.Context) {
	/*将数据转为json后在进行base64编码*/
	var err error
	msg := ctx.DefaultQuery("msg", "")
	cols := ctx.DefaultQuery("cols", "150")
	rows := ctx.DefaultQuery("rows", "35")
	col, _ := strconv.Atoi(cols)
	row, _ := strconv.Atoi(rows)

	terminal := Terminal{
		Columns: uint32(col),
		Rows:    uint32(row),
	}
	sshClient, err := DecodedMsgToSSHClient(msg)
	if err != nil {
		global.TPLogger.Error(err)
		utils.ReturnContext(ctx).Failed("失败", err)
		return
	}
	if sshClient.IpAddress == "" || sshClient.Password == "" {
		utils.ReturnContext(ctx).Failed("失败", errors.New("IP地址或密码不能为空"))
		//ctx.Error(&utils.ApiError{Message: "IP地址或密码不能为空", Code: 400})
		return
	}

	//upgrader := websocket.Upgrader{}
	conn, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		utils.ReturnContext(ctx).Failed("失败", err)
		return
	}
	err = sshClient.GenerateClient()
	if err != nil {
		conn.WriteMessage(1, []byte(err.Error()))
		conn.Close()
		return
	}
	sshClient.RequestTerminal(terminal)
	sshClient.Connect(conn)
}
